<template>
  <j-modal :title="title" :width="width" :visible="visible" :confirmLoading="confirmLoading" switchFullscreen @ok="handleOk" @cancel="handleCancel" cancelText="关闭">
    <a-spin :spinning="confirmLoading">
      <a-form :form="form">
        <a-form-item label="考勤组名称" :labelCol="labelCol" :wrapperCol="wrapperCol">
          <a-input :disabled="(readOnly || isEdit)" v-decorator="['name', {
            rules: [
              { required: true, message: '请输入考勤组名称' }
            ]
          }]" placeholder="请输入考勤组名称"></a-input>
        </a-form-item>
        <a-form-item label="正常取值类型" :labelCol="labelCol" :wrapperCol="wrapperCol">
          <!-- <a-input v-decorator="['attendanceTimeRulesId',]" placeholder="请选择考勤时间规则"></a-input> -->
          <a-select :disabled="readOnly" style="width: 200px" v-decorator="['attendanceTimeRulesId', 
            {
               rules: [
              { required: true, message: '请选择考勤时间规则' }
            ]
            }
            ]" placeholder="请选择考勤时间规则">
            <a-select-option v-for="record of selectDataSource" :value="record.attendanceTimeRulesId" :key="record.attendanceTimeRulesId">
              {{record.name}}
            </a-select-option>
          </a-select>
        </a-form-item>
        <a-form-item>
          <a-transfer 
            class="tree-transfer"
            :data-source="dataSource" 
            :target-keys="targetKeys" 
            :render="item => item.title" 
            :disabled="readOnly"
            :show-select-all="false" 
            @change="onChange"
            >
            <template slot="children" slot-scope="{ props: { direction, selectedKeys }, on: { itemSelect, itemSelectAll } }">
              <a-tree v-if="direction === 'left'" blockNode checkable checkStrictly defaultExpandAll :checkedKeys="[...selectedKeys, ...targetKeys]" :treeData="processedTreeData" @check="
                  (_, props) => {
                    onChecked(_, props, [...selectedKeys, ...targetKeys], itemSelectAll);
                  }
                " @select="
                  (_, props) => {
                    onChecked(_, props, [...selectedKeys, ...targetKeys], itemSelectAll);
                  }
               " />
            </template>
          </a-transfer>
        </a-form-item>
      </a-form>
    </a-spin>
    <template slot="footer">
      <a-button @click="handleCancel">关闭</a-button>
      <a-button @click="handleOk" type="primary" v-if="!readOnly">确认</a-button>
    </template>
  </j-modal>
</template>

<script>
import { httpAction } from '@/api/manage'
import lodash from 'lodash'
import JDate from '@/components/jeecg/JDate'
import { isChecked, getAllKeys, isCheckedAll, hasSelectedAll, isEmptyDept } from '../utils'
export default {
  name: 'AttendanceGroupSettingModal',
  components: {
    JDate,
  },
  data() {
    return {
      form: this.$form.createForm(this),
      title: '操作',
      width: 1000,
      visible: false,
      model: {},
      labelCol: {
        xs: { span: 24 },
        sm: { span: 5 },
      },
      wrapperCol: {
        xs: { span: 24 },
        sm: { span: 16 },
      },
      confirmLoading: false,
      validatorRules: {},
      url: {
        add: '/attendanceGroupSetting/attendanceGroupSetting/addTeacherToGroup',
        edit: '/attendanceGroupSetting/attendanceGroupSetting/editTeacherFromGroup',
        getuser: '/attendanceGroupSetting/attendanceGroupSetting/queryTreeList',
      },
      // 穿梭框数据源
      dataSource: [],
      // 点击元素的Keys
      targetKeys: [],
      // 树状数据
      treeData: [],
      // 选择器数据源
      selectDataSource: [],
      selectedKeys: [],
      // 是否为编辑模式
      isEdit: false,
      // 全局保存当前打开的部门Id
      deptId: '',
      // 只读模式
      readOnly: false,
      // 处理加工之后树结构列表
      processedTreeData: [],
    }
  },
  created() {
    this.getTimeRules()
  },
  methods: {
    add() {
      this.targetKeys = []
      this.edit({})
    },
    async edit(record, readOnly) {
      // 根据是否传入第二个参数判断当前是否为详情查看模式
      // 若没传入第二个参数根据undefined的隐式类型转换
      // 判断为编辑状态
      record && (this.isEdit = true)
      this.model = Object.assign({}, record)
      this.readOnly = readOnly
      this.form.resetFields()
      // 初始化已选中老师列表, 重新init一次树结构，避免残留数据影响各节点disabled的判断
      await this.getusers()
      // 保存该考勤组的老师列表，以进行数据的回显
      record.attendanceGroupTeacherList &&
        (this.targetKeys = record.attendanceGroupTeacherList.map((item) => item.attendanceTeacherId))
      // 保存当前考情组的ID, 用以禁止非当前的考勤组选择的成员
      record.id && (this.deptId = record.id)

      this.visible = true
      this.$nextTick(() => {
        this.form.setFieldsValue(lodash.pick(this.model, 'name', 'attendanceTimeRulesId', 'attendanceGroupTeacherList'))
      })
    },
    /**
     * 关闭时要对数据进行置空，避免残留数据影响树结构规则的判断
     */
    close() {
      this.selectedKeys = []
      // 初始化选中列表
      this.targetKeys = []
      this.processedTreeData = []
      this.deptId = ''
      this.$emit('close')
      this.visible = false
    },
    handleOk() {
      const that = this
      const targetKeys = this.targetKeys,
        isEdit = this.isEdit
      // 触发表单验证
      if (!isEdit && (!targetKeys || targetKeys.length === 0)) {
        return this.$message.error('请先选择考勤组成员')
      }
      this.form.validateFields((err, values) => {
        if (!err) {
          that.confirmLoading = true
          let httpurl = ''
          let method = ''
          if (!this.model.id) {
            httpurl += this.url.add
            method = 'post'
          } else {
            httpurl += this.url.edit
            method = 'put'
          }
          let formData = Object.assign(this.model, values)
          formData.attendanceGroupTeacherList = targetKeys.map((item) => ({ attendanceTeacherId: item }))
          console.log('表单提交数据', formData)
          httpAction(httpurl, formData, method)
            .then((res) => {
              if (res.success) {
                that.$message.success(res.message)
                that.$emit('ok')
                that.close()
              } else {
                that.$message.warning(res.message)
              }
            })
            .finally(() => {
              that.confirmLoading = false             
            })
        }
      })
    },
    handleCancel() {
      this.close()
    },
    popupCallback(row) {
      this.form.setFieldsValue(lodash.pick(row, 'name', 'attendanceTimeRulesId'))
    },
    async getusers() {
      try {
        const { code, success, result } = await httpAction(this.url.getuser, {}, 'get')
        if (code === 0 && success) {
          // 扁平化写法问题, 可以修改flatten函数, 或扁平化前初始化数据源列表
          this.dataSource = []
          // 扁平化
          this.flatten(result, this.dataSource)
          this.treeData = result
          // 初始化树的选择规则
          this.initTreeRules()
        }
      } catch (e) {
        console.log(e)
      }
    },
    // 穿梭框选择事件
    onChange(targetKeys) {
      console.log('Target Keys:', targetKeys)
      this.targetKeys = targetKeys
      // 穿梭完成, 重新构建树结构规则
      this.initTreeRules()
      this.$nextTick(() => {
        // 判断一次部门全选状态
        this.changeDeptStatus(this.processedTreeData)
        // 强制页面数据更新一次
        this.$forceUpdate()
      })
    },
    initTreeRules() {
      this.processedTreeData = this.handleTreeDataPersons(lodash.cloneDeep(this.treeData), this.targetKeys)
      this.processedTreeData = this.handleTreeDataDepts(this.processedTreeData, this.targetKeys)
    },
    // 树状结构检验事件
    onChecked(_, e, checkedKeys, itemSelectAll) {
      const { eventKey } = e.node,
        tempArr = [];
      // 这里要获取到带有disabled属性的加工后的树结构进行扁平化    
      // 用以排除掉已经被选中、不可选的老师成员
      this.flatten(this.processedTreeData, tempArr)
      const eventItem = tempArr.find((item) => item.key === eventKey),
        // getALlKeys 得到该部门下所有可选中的成员列表
        selectedAll = getAllKeys(eventItem)
      // 选中所有keys
      itemSelectAll(selectedAll, !isCheckedAll(checkedKeys, selectedAll))
    },
    /**
     *  将树形结构数据扁平化
     */
    flatten(treeData = [], dataSource) {
      if (!dataSource) {
        return []
      }
      treeData.forEach((item) => {
        dataSource.push({ ...item })
        item.children && this.flatten(item.children, dataSource)
      })
    },
    /**
     * 查询事件规则id -> 组成dropdown数据源
     */
    async getTimeRules() {
      const {
        result: { records },
      } = await httpAction('/attendanceTimeRules/attendanceTimeRules/list', '', 'get')
      this.selectDataSource = records.map((record) => ({ attendanceTimeRulesId: record.id, name: record.name }))
    },
    /**
     * 对树结构的成员部分进行处理
     * @param {*} data 数据源
     * @param {*} targetKeys 已选中老师列表
     */
    handleTreeDataPersons(data, targetKeys = []) {
      const deptId = this.deptId
      data.forEach((item) => {
        // 匹配人员
        if (item.isDept === false) {
          // 1. 用户已经在已选状态
          item['disabled'] =
            targetKeys.includes(item.key) ||
            (!targetKeys.includes(item.key) && item.attendanceGroupId && item.attendanceGroupId != deptId)
        } else {
          if (item.children) {
            this.handleTreeDataPersons(item.children, targetKeys)
          }
        }
      })
      return data
    },
    /**
     * 对树结构的部门部分进行处理
     * @param {*} data 数据源
     * @param {*} targetKeys 已选中老师列表
     */
    handleTreeDataDepts(data, targetKeys = []) {
      data.forEach((item) => {
        if (item.isDept === true) {
          item.disabled = isEmptyDept(item) || hasSelectedAll(item)
          if (item.children) {
            this.handleTreeDataDepts(item.children, targetKeys)
          }
        }
      })
      return data
    },

    /**
     * 刷新部门选中状态
     * @param {*} data 部门
     */
    changeDeptStatus(data) {
      data.forEach((item) => {
        if (item.isDept === true) {          
          item.disabled = hasSelectedAll(item)
          if (item.children) {
            this.changeDeptStatus(item.children)
          }
        }
      })
    },
  },
}
</script>